class IUP_TABS
-- Creates a native container for composing elements in hidden layers with only 
-- one layer visible (just like IUP_ZBOX), but its visibility can be 
-- interactively controlled. The interaction is done in a line of tabs with 
-- titles and arranged according to the tab type. Also known as Notebook in 
-- native systems.

inherit
	IUP_ZBOX
		rename
			zbox_empty as tabs_empty
			zbox as tabs
		redefine
			tabs_empty,
			tabs,
			execute_map,
			execute_unmap,
			execute_destroy,
			execute_getfocus,
			execute_killfocus,
			execute_enterwindow,
			execute_leavewindow,
			execute_k_any,
			execute_help,
			execute_tabchange,
			execute_tabchangepos,
			execute_tabclose,
			execute_rightclick,
			execute_focus
		end
	IUP_WIDGET_BGCOLOR
	IUP_WIDGET_EXPAND
	IUP_WIDGET_FGCOLOR
	IUP_WIDGET_SIZE
	IUP_WIDGET_ACTIVE
	IUP_WIDGET_FONT
	IUP_WIDGET_SCREENPOSITION
	IUP_WIDGET_POSITION
	IUP_WIDGET_CLIENTSIZE
	IUP_WIDGET_CLIENTOFFSET
	IUP_WIDGET_MAXMIN_SIZE
	IUP_WIDGET_TIP
	IUP_WIDGET_RASTERSIZE
	IUP_WIDGET_USERSIZE
	IUP_WIDGET_ZORDER
	IUP_WIDGET_VISIBLE
	IUP_WIDGET_CHILD
	IUP_WIDGET_NAME
	IUP_WIDGET_FOCUS
	IUP_WIDGET_PROPAGATEFOCUS
	IUP_WIDGET_FLOATING
	IUP_WIDGET_CHILDSIZEALL

create {ANY}
	tabs_empty,
	tabs

feature {ANY}

	tabs_empty
	   -- Create an empty tabs
		local
			p, a_tabs: POINTER
		do
			a_tabs := int_tabs_empty (p)
			set_widget(a_tabs)
		end
		
	tabs (col: ARRAY[IUP_WIDGET])
	   -- Create a new tabs containing the list of widgets
		local
         iterator: ITERATOR[IUP_WIDGET]; i: INTEGER; arg: NATIVE_ARRAY[POINTER]; s: IUP_WIDGET; a_tabs: POINTER
		do
			i := col.count
			arg := arg.calloc(i)
			iterator := col.new_iterator
			i := 0
			
			from
				iterator.start
         until
				iterator.is_off
         loop
            s := iterator.item
            arg.put(s.widget, i)
				iterator.next
            i := i + 1
         end

			a_tabs := int_tabs (arg.to_external)
			set_widget(a_tabs)
		end

	-- Attributes
	set_childoffset (horizontal, vertical: INTEGER)
		require
			horizontal >= 0
			vertical >= 0
		local
			offset: STRING
		do
			offset := horizontal.to_string
			offset.append_string("x")
			offset.append_string(vertical.to_string)

			iup_open.set_attribute(Current, "CHILDOFFSET", offset)
		end

	get_childoffset: TUPLE[INTEGER, INTEGER]
		-- Return the offset of the child.
		local
			offset: STRING
		do
			offset := iup_open.get_attribute(Current, "CHILDOFFSET")
			Result := components_of_size(offset)
		end
	
	count: INTEGER
		-- (read-only) (non inheritable): returns the number of tabs.
		do
			Result := get_child_count
		end

	set_multiline (state: BOOLEAN)
		-- [Windows Only] (non inheritable): Enable multiple lines of tab 
		-- buttons. This will hide the tab scroll and fits to make all tab buttons
		-- visible. Can be "YES" or "NO". Default "NO". It is always enabled 
		-- when TABTYPE=LEFT or TABTYPE=RIGHT.
		do
			iup_open.set_attribute(Current, "MULTILINE", boolean_to_yesno(state))
		end

	is_multiline: BOOLEAN
		-- Return the multiline status of the element.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "MULTILINE")
			Result := yesno_to_boolean(str)
		end

	set_showclose (state: BOOLEAN)
		-- [Windows and GTK Only] (non inheritable): enables the close button on 
		-- each tab. Default value: "NO". In Windows the close button imply the 
		-- classic visual for the control. By default when closed the tab is 
		-- hidden. The change that behavior use the TABCLOSE_CB callback.
		do
			iup_open.set_attribute(Current, "SHOWCLOSE", boolean_to_yesno(state))
		end

	is_showclose: BOOLEAN
		-- Return the showclose status of the element.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "SHOWCLOSE")
			Result := yesno_to_boolean(str)
		end

	set_horizontal_tab
		-- (non inheritable): Indicates an horizontal orientation of tab text. 
		-- This is the default value. In Windows, it can NOT be set, 
		-- it is dependent on the TABTYPE attribute, if TABTYPE=LEFT or 
		-- TABTYPE=RIGHT then TABORIENTATION=VERTICAL, if TABTYPE=TOP or 
		-- TABTYPE=BOTTOM then TABORIENTATION=HORIZONTAL.
		do
			iup_open.set_attribute(Current, "TABORIENTATION", "HORIZONTAL")	
		end
	
	set_vertical_tab
		-- (non inheritable): Indicates a vertical orientation of tab text. 
		-- VERTICAL is supported only in GTK and in Windows. In Windows, it can 
		-- NOT be set, it is dependent on the TABTYPE attribute, if TABTYPE=LEFT 
		-- or TABTYPE=RIGHT then TABORIENTATION=VERTICAL, if TABTYPE=TOP or 
		-- TABTYPE=BOTTOM then TABORIENTATION=HORIZONTAL.
		do
			iup_open.set_attribute(Current, "TABORIENTATION", "VERTICAL")	
		end

	is_horizontal_tab: BOOLEAN
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "TABORIENTATION")

			if str.is_equal("HORIZONTAL") then
				Result := True
			else
				Result := False
			end
		end

	is_vertical_tab: BOOLEAN
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "TABORIENTATION")

			if str.is_equal("VERTICAL") then
				Result := True
			else
				Result := False
			end
		end

	set_tab_padding (horizontal, vertical: INTEGER)
		-- (non inheritable): internal margin of the tab title. Works just like 
		-- the MARGIN attribute of the IUP_BOX and IUP_VBOX containers, but uses 
		-- a different name to avoid inheritance problems. Default value: "0x0".
		require
			horizontal >= 0
			vertical >= 0
		local
			padding: STRING
		do
			padding := horizontal.to_string
			padding.append_string("x")
			padding.append_string(vertical.to_string)

			iup_open.set_attribute(Current, "TABPADDING", padding)
		end

	get_tab_padding: TUPLE[INTEGER, INTEGER]
		-- Return the margin of the tab title.
		local
			padding: STRING
		do
			padding := iup_open.get_attribute(Current, "TABPADDING")
			Result := components_of_size(padding)
		end

	set_tab_type (type: STRING)
		-- (non inheritable) (creation only in Windows): Indicates the type of 
		-- tab, which can be "TOP", "BOTTOM", "LEFT" or "RIGHT". Default is "TOP".
		-- In Windows, if LEFT or RIGHT then MULTILINE=YES and 
		-- TABORIENTATION=VERTICAL are set, if TOP or BOTTOM then 
		-- TABORIENTATION=HORIZONTAL is set. In Windows, when not TOP, then 
		-- visual style is removed from tabs.
		require
			is_valid_tabtype(type)
		do
			iup_open.set_attribute (Current, "TABTYPE", type)
		end

	get_tab_type: STRING
		-- Return the tab type.
		do
			Result := iup_open.get_attribute (Current, "TABTYPE")
		end

	-- Tab attributes

	set_tab_n_image (imagename: STRING; n: INTEGER)
		-- (non inheritable): image name to be used in the respective tab. Use 
		-- set_attribute_handle to associate an image to a name. n starts at 0. 
		-- See also IUP_IMAGE. In Motif, the image is shown only if TABTITLEn is 
		-- Void. In Windows and Motif set the BGCOLOR attribute before setting 
		-- the image. When set after map will update the TABIMAGE attribute on 
		-- the respective child
		require
			n >= 0
		local
			str: STRING
		do
			str := "TABIMAGE" + n.to_string
			iup_open.set_attribute (Current, str, imagename)
		end

	get_tab_n_image (n: INTEGER): STRING
   	-- Return the image name at tab n.
		require
		   n >= 0
		local
			str: STRING
		do
			str := "TABIMAGE" + n.to_string
			Result := iup_open.get_attribute(Current, str)
		end

	set_tab_n_visible (state: BOOLEAN; n: INTEGER)
		-- Allows to hide a tab. n starts at 0. When a tab is hidden the tabs 
		-- indices are not changed.
		require
			n >= 0
		do
			iup_open.set_attribute_id (Current, "TABVISIBLE", n, boolean_to_yesno(state))
		end

	is_tab_n_visible (n: INTEGER): BOOLEAN
   	-- Return the visible status of tab n.
		require
		   n >= 0
		local
			str: STRING
		do
			str := iup_open.get_attribute_id(Current, "TABVISIBLE", n)
			Result := yesno_to_boolean(str)
		end

	set_tab_n_title (title: STRING; n: INTEGER)
		-- (non inheritable): Contains the text to be shown in the respective 
		-- tab title. n starts at 0. The "&" character can be used to define a 
		-- mnemonic, the next character will be used as key. Use "&&" to show the 
		-- "&" character instead on defining a mnemonic. The button can be 
		-- activated from any control in the dialog using the "Alt+key" 
		-- combination. When set after map will update the TABTITLE attribute on 
		-- the respective child.
		require
			n >= 0
		do
			iup_open.set_attribute_id (Current, "TABTITLE", n, title)
		end

	get_tab_n_title (n: INTEGER): STRING
   	-- Return the title of tab n.
		require
		   n >= 0
		do
			Result := iup_open.get_attribute_id(Current, "TABTITLE", n)
		end

	-- Callbacks

	-- Common
	set_cb_map (act: FUNCTION[TUPLE[IUP_TABS], STRING])
		-- Called right after an element is mapped and its attributes updated.
		local
			operation: INTEGER
		do
			cb_map := act
			
			if cb_map /= Void then
				operation := 1
			else
				operation := 0
			end
						
			iup_open.set_callback (Current, "MAP_CB", "NONEEDED", operation)
		end

	set_cb_unmap (act: FUNCTION[TUPLE[IUP_TABS], STRING])
		-- Called right before an element is unmapped.
		local
			operation: INTEGER
		do
			cb_unmap := act

			if cb_unmap /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "UNMAP_CB", "NONEEDED", operation)
		end

	set_cb_destroy (act: FUNCTION[TUPLE[IUP_TABS], STRING])
		-- Called right before an element is destroyed.
		local
			operation: INTEGER
		do
			cb_destroy := act

			if cb_destroy /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "DESTROY_CB", "NONEEDED", operation)
		end

	set_cb_get_focus (act: FUNCTION[TUPLE[IUP_TABS], STRING])
		-- Action generated when an element is given keyboard focus. 
		-- This callback is called after the KILLFOCUS_CB of the element 
		-- that loosed the focus. The {IUP}.get_focus function during the 
		-- callback returns the element that loosed the focus.
		local
			operation: INTEGER
		do
			cb_getfocus := act

			if cb_getfocus /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "GETFOCUS_CB", "NONEEDED", operation)
		end

	set_cb_kill_focus (act: FUNCTION[TUPLE[IUP_TABS], STRING])
		-- Action generated when an element loses keyboard focus. This 
		-- callback is called before the GETFOCUS_CB of the element that 
		-- gets the focus.
		local
			operation: INTEGER
		do
			cb_killfocus := act

			if cb_killfocus /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "KILLFOCUS_CB", "NONEEDED", operation)
		end

	set_cb_enter_window (act: FUNCTION[TUPLE[IUP_TABS], STRING])
		-- Action generated when the mouse enters the native element. 
		local
			operation: INTEGER
		do
			cb_enterwindow := act

			if cb_enterwindow /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "ENTERWINDOW_CB", "NONEEDED", operation)
		end

	set_cb_leave_window (act: FUNCTION[TUPLE[IUP_TABS], STRING])
		-- Action generated when the mouse leaves the native element.
		local
			operation: INTEGER
		do
			cb_leavewindow := act

			if cb_leavewindow /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "LEAVEWINDOW_CB", "NONEEDED", operation)
		end

	set_cb_k_any (act: FUNCTION[TUPLE[IUP_TABS, INTEGER], STRING])
		-- Action generated when a keyboard event occurs.
		-- IUP_WIDGET the element that activated the event.
		-- INTEGER identifier of typed key. Please refer to the Keyboard 
		-- Codes table for a list of possible values.
		--
		-- Returns: If IUP_IGNORE is returned the key is ignored and not
		-- processed by the control and not propagated. If returns 
		-- IUP_CONTINUE, the key will be processed and the event will be
		-- propagated to the parent of the element receiving it, this is 
		-- the default behavior. If returns IUP_DEFAULT the key is processed 
		-- but it is not propagated. IUP_CLOSE will be processed. 
		local
			operation: INTEGER
		do
			cb_k_any := act

			if cb_k_any /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "K_ANY", "NONEEDED", operation)
		end

	set_cb_help (act: PROCEDURE[TUPLE[IUP_TABS]])
		-- Action generated when the user press F1 at a control. In Motif 
		-- is also activated by the Help button in some workstations 
		-- keyboard.
		-- Returns: IUP_CLOSE will be processed.
		local
			operation: INTEGER
		do
			cb_help := act

			if cb_help /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "HELP_CB", "NONEEDED", operation)
		end

	-- Extra
	set_cb_tab_change (act: FUNCTION[TUPLE[IUP_TABS, IUP_WIDGET, IUP_WIDGET], STRING])
		-- Callback called when the user shifts the active tab.
		local
			operation: INTEGER
		do
			cb_tabchange := act

			if cb_tabchange /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "TABCHANGE_CB", "NONEEDED", operation)
		end

	set_cb_tab_change_position (act: FUNCTION[TUPLE[IUP_TABS, INTEGER, INTEGER], STRING])
		-- Callback called when the user shifts the active tab. Called only when 
		-- TABCHANGE_CB is not defined.
		local
			operation: INTEGER
		do
			cb_tabchangepos := act

			if cb_tabchangepos /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "TABCHANGEPOS_CB", "NONEEDED", operation)
		end

	set_cb_tab_close (act: FUNCTION[TUPLE[IUP_TABS, INTEGER], STRING])
		-- [Windows and GTK Only]: Callback called when the user clicks on the 
		-- close button. Called only when SHOWCLOSE=Yes.
		local
			operation: INTEGER
		do
			cb_tabclose := act

			if cb_tabclose /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "TABCLOSE_CB", "NONEEDED", operation)
		end

	set_cb_right_click (act: FUNCTION[TUPLE[IUP_TABS, INTEGER], STRING])
		-- Callback called when the user clicks on some tab using the right mouse 
		-- button.
		local
			operation: INTEGER
		do
			cb_rightclick := act

			if cb_rightclick /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "RIGHTCLICK_CB", "NONEEDED", operation)
		end

	set_cb_focus (act: FUNCTION[TUPLE[IUP_TABS, INTEGER], STRING])
		-- Called when a child of the container gets or looses the focus. It is 
		-- called only if PROPAGATEFOCUS is defined in the child.
		local
			operation: INTEGER
		do
			cb_focus := act

			if cb_focus /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "FOCUS_CB", "NONEEDED", operation)
		end
				
feature {ANY}
	
	-- Callbacks
	execute_map: STRING
		do
			Result := cb_map.item([Current])
		end

	execute_unmap: STRING
		do
			Result := cb_unmap.item([Current])
		end

	execute_destroy: STRING
		do
			Result := cb_destroy.item([Current])
		end

	execute_getfocus: STRING
		do
			Result := cb_getfocus.item([Current])
		end

	execute_killfocus: STRING
		do
			Result := cb_getfocus.item([Current])
		end

	execute_enterwindow: STRING
		do
			Result := cb_enterwindow.item([Current])
		end

	execute_leavewindow: STRING
		do
			Result := cb_leavewindow.item([Current])
		end

	execute_k_any (c: INTEGER): STRING
		do
			Result := cb_k_any.item([Current, c])
		end

	execute_help
		do
			cb_help.call([Current])
		end
	
	execute_tabchange (new_tab, old_tab: IUP_WIDGET): STRING
		do
			Result := cb_tabchange.item([Current, new_tab, old_tab])
		end

	execute_tabchangepos (new_pos, old_pos: INTEGER): STRING
		do
			Result := cb_tabchangepos.item([Current, new_pos, old_pos])
		end

	execute_tabclose (pos: INTEGER): STRING
		do
			Result := cb_tabclose.item([Current, pos])
		end

	execute_rightclick (pos: INTEGER): STRING
		do
			Result := cb_rightclick.item([Current, pos])
		end

	execute_focus (focus: INTEGER): STRING
		do
			Result := cb_focus.item([Current, focus])
		end

	feature {}

	-- For Tabs callbacks
	
	cb_map: FUNCTION[TUPLE[IUP_TABS], STRING]
	cb_unmap: FUNCTION[TUPLE[IUP_TABS], STRING]
	cb_destroy: FUNCTION[TUPLE[IUP_TABS], STRING]
	cb_getfocus: FUNCTION[TUPLE[IUP_TABS], STRING]
	cb_killfocus: FUNCTION[TUPLE[IUP_TABS], STRING]
	cb_enterwindow: FUNCTION[TUPLE[IUP_TABS], STRING]
	cb_leavewindow: FUNCTION[TUPLE[IUP_TABS], STRING]
	cb_k_any: FUNCTION[TUPLE[IUP_TABS, INTEGER], STRING]
	cb_help: PROCEDURE[TUPLE[IUP_TABS]]
	cb_action: FUNCTION[TUPLE[IUP_TABS], STRING]
	
	cb_tabchange: FUNCTION[TUPLE[IUP_TABS, IUP_WIDGET, IUP_WIDGET], STRING]
	cb_tabchangepos: FUNCTION[TUPLE[IUP_TABS, INTEGER, INTEGER], STRING]
	cb_tabclose: FUNCTION[TUPLE[IUP_TABS, INTEGER], STRING]
	cb_rightclick: FUNCTION[TUPLE[IUP_TABS, INTEGER], STRING]
	cb_focus: FUNCTION[TUPLE[IUP_TABS, INTEGER], STRING]

	-- Internals
	
	int_tabs_empty (arguments: POINTER): POINTER
		external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupTabs"
         }"
      end
	
   int_tabs (arguments: POINTER): POINTER
		external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupTabsv"
         }"
      end

	-- Validations

	is_valid_tabtype (type: STRING):  BOOLEAN
		do
			if type.is_equal("TOP") or
				type.is_equal("BOTTOM") or
				type.is_equal("LEFT") or
				type.is_equal("RIGHT") then
				Result := True
			else
				Result := False
			end
		end
end

-- The MIT License (MIT)

-- Copyright (c) 2016, 2017, 2019 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
